home *** CD-ROM | disk | FTP | other *** search
/ Risc World 3 / Risc World 3.iso / SOFTWARE / ISSUE6 / PD / PDF / xpdf / c++ / GfxState < prev   
Text File  |  2003-02-21  |  59KB  |  2,373 lines

  1. //========================================================================
  2. //
  3. // GfxState.cc
  4. //
  5. // Copyright 1996-2002 Glyph & Cog, LLC
  6. //
  7. //========================================================================
  8.  
  9. //========================================================================
  10. //
  11. // Changes marked:
  12. //
  13. //   //**** Colin Granville ****
  14. // To
  15. //   //**** end Colin Granville ****
  16. //
  17. // made by Colin Granville 2003
  18. //
  19. //========================================================================
  20.  
  21. #include <aconf.h>
  22.  
  23. #ifdef USE_GCC_PRAGMAS
  24. #pragma implementation
  25. #endif
  26.  
  27. #include <stddef.h>
  28. #include <math.h>
  29. #include <string.h> // for memcpy()
  30. #include "gmem.h"
  31. #include "Error.h"
  32. #include "Object.h"
  33. #include "Array.h"
  34. #include "Page.h"
  35. #include "GfxState.h"
  36.  
  37. //------------------------------------------------------------------------
  38.  
  39. static inline double clip01(double x) {
  40.   return (x < 0) ? 0 : ((x > 1) ? 1 : x);
  41. }
  42.  
  43. //------------------------------------------------------------------------
  44.  
  45. static char *gfxColorSpaceModeNames[] = {
  46.   "DeviceGray",
  47.   "CalGray",
  48.   "DeviceRGB",
  49.   "CalRGB",
  50.   "DeviceCMYK",
  51.   "Lab",
  52.   "ICCBased",
  53.   "Indexed",
  54.   "Separation",
  55.   "DeviceN",
  56.   "Pattern"
  57. };
  58.  
  59. #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
  60.  
  61. //------------------------------------------------------------------------
  62. // GfxColorSpace
  63. //------------------------------------------------------------------------
  64.  
  65. GfxColorSpace::GfxColorSpace() {
  66. }
  67.  
  68. GfxColorSpace::~GfxColorSpace() {
  69. }
  70.  
  71. GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
  72.   GfxColorSpace *cs;
  73.   Object obj1;
  74.  
  75.   cs = NULL;
  76.   if (csObj->isName()) {
  77.     if (csObj->isName("DeviceGray") || csObj->isName("G")) {
  78.       cs = new GfxDeviceGrayColorSpace();
  79.     } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
  80.       cs = new GfxDeviceRGBColorSpace();
  81.     } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
  82.       cs = new GfxDeviceCMYKColorSpace();
  83.     } else if (csObj->isName("Pattern")) {
  84.       cs = new GfxPatternColorSpace(NULL);
  85.     } else {
  86.       error(-1, "Bad color space '%s'", csObj->getName());
  87.     }
  88.   } else if (csObj->isArray()) {
  89.     csObj->arrayGet(0, &obj1);
  90.     if (obj1.isName("DeviceGray") || obj1.isName("G")) {
  91.       cs = new GfxDeviceGrayColorSpace();
  92.     } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
  93.       cs = new GfxDeviceRGBColorSpace();
  94.     } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
  95.       cs = new GfxDeviceCMYKColorSpace();
  96.     } else if (obj1.isName("CalGray")) {
  97.       cs = GfxCalGrayColorSpace::parse(csObj->getArray());
  98.     } else if (obj1.isName("CalRGB")) {
  99.       cs = GfxCalRGBColorSpace::parse(csObj->getArray());
  100.     } else if (obj1.isName("Lab")) {
  101.       cs = GfxLabColorSpace::parse(csObj->getArray());
  102.     } else if (obj1.isName("ICCBased")) {
  103.       cs = GfxICCBasedColorSpace::parse(csObj->getArray());
  104.     } else if (obj1.isName("Indexed") || obj1.isName("I")) {
  105.       cs = GfxIndexedColorSpace::parse(csObj->getArray());
  106.     } else if (obj1.isName("Separation")) {
  107.       cs = GfxSeparationColorSpace::parse(csObj->getArray());
  108.     } else if (obj1.isName("DeviceN")) {
  109.       cs = GfxDeviceNColorSpace::parse(csObj->getArray());
  110.     } else if (obj1.isName("Pattern")) {
  111.       cs = GfxPatternColorSpace::parse(csObj->getArray());
  112.     } else {
  113.       error(-1, "Bad color space '%s'", csObj->getName());
  114.     }
  115.     obj1.free();
  116.   } else {
  117.     error(-1, "Bad color space - expected name or array");
  118.   }
  119.   return cs;
  120. }
  121.  
  122. void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
  123.                                      int maxImgPixel) {
  124.   int i;
  125.  
  126.   for (i = 0; i < getNComps(); ++i) {
  127.     decodeLow[i] = 0;
  128.     decodeRange[i] = 1;
  129.   }
  130. }
  131.  
  132. int GfxColorSpace::getNumColorSpaceModes() {
  133.   return nGfxColorSpaceModes;
  134. }
  135.  
  136. char *GfxColorSpace::getColorSpaceModeName(int idx) {
  137.   return gfxColorSpaceModeNames[idx];
  138. }
  139.  
  140. //------------------------------------------------------------------------
  141. // GfxDeviceGrayColorSpace
  142. //------------------------------------------------------------------------
  143.  
  144. GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
  145. }
  146.  
  147. GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
  148. }
  149.  
  150. GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
  151.   return new GfxDeviceGrayColorSpace();
  152. }
  153.  
  154. void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
  155.   *gray = clip01(color->c[0]);
  156. }
  157.  
  158. void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  159.   rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
  160. }
  161.  
  162. void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  163.   cmyk->c = cmyk->m = cmyk->y = 0;
  164.   cmyk->k = clip01(1 - color->c[0]);
  165. }
  166.  
  167. //------------------------------------------------------------------------
  168. // GfxCalGrayColorSpace
  169. //------------------------------------------------------------------------
  170.  
  171. GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
  172.   whiteX = whiteY = whiteZ = 1;
  173.   blackX = blackY = blackZ = 0;
  174.   gamma = 1;
  175. }
  176.  
  177. GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
  178. }
  179.  
  180. GfxColorSpace *GfxCalGrayColorSpace::copy() {
  181.   GfxCalGrayColorSpace *cs;
  182.  
  183.   cs = new GfxCalGrayColorSpace();
  184.   cs->whiteX = whiteX;
  185.   cs->whiteY = whiteY;
  186.   cs->whiteZ = whiteZ;
  187.   cs->blackX = blackX;
  188.   cs->blackY = blackY;
  189.   cs->blackZ = blackZ;
  190.   cs->gamma = gamma;
  191.   return cs;
  192. }
  193.  
  194. GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
  195.   GfxCalGrayColorSpace *cs;
  196.   Object obj1, obj2, obj3;
  197.  
  198.   arr->get(1, &obj1);
  199.   if (!obj1.isDict()) {
  200.     error(-1, "Bad CalGray color space");
  201.     obj1.free();
  202.     return NULL;
  203.   }
  204.   cs = new GfxCalGrayColorSpace();
  205.   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
  206.       obj2.arrayGetLength() == 3) {
  207.     obj2.arrayGet(0, &obj3);
  208.     cs->whiteX = obj3.getNum();
  209.     obj3.free();
  210.     obj2.arrayGet(1, &obj3);
  211.     cs->whiteY = obj3.getNum();
  212.     obj3.free();
  213.     obj2.arrayGet(2, &obj3);
  214.     cs->whiteZ = obj3.getNum();
  215.     obj3.free();
  216.   }
  217.   obj2.free();
  218.   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
  219.       obj2.arrayGetLength() == 3) {
  220.     obj2.arrayGet(0, &obj3);
  221.     cs->blackX = obj3.getNum();
  222.     obj3.free();
  223.     obj2.arrayGet(1, &obj3);
  224.     cs->blackY = obj3.getNum();
  225.     obj3.free();
  226.     obj2.arrayGet(2, &obj3);
  227.     cs->blackZ = obj3.getNum();
  228.     obj3.free();
  229.   }
  230.   obj2.free();
  231.   if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
  232.     cs->gamma = obj2.getNum();
  233.   }
  234.   obj2.free();
  235.   obj1.free();
  236.   return cs;
  237. }
  238.  
  239. void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
  240.   *gray = clip01(color->c[0]);
  241. }
  242.  
  243. void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  244.   rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
  245. }
  246.  
  247. void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  248.   cmyk->c = cmyk->m = cmyk->y = 0;
  249.   cmyk->k = clip01(1 - color->c[0]);
  250. }
  251.  
  252. //------------------------------------------------------------------------
  253. // GfxDeviceRGBColorSpace
  254. //------------------------------------------------------------------------
  255.  
  256. GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
  257. }
  258.  
  259. GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
  260. }
  261.  
  262. GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
  263.   return new GfxDeviceRGBColorSpace();
  264. }
  265.  
  266. void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
  267.   *gray = clip01(0.299 * color->c[0] +
  268.                  0.587 * color->c[1] +
  269.                  0.114 * color->c[2]);
  270. }
  271.  
  272. void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  273.   rgb->r = clip01(color->c[0]);
  274.   rgb->g = clip01(color->c[1]);
  275.   rgb->b = clip01(color->c[2]);
  276. }
  277.  
  278. void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  279.   double c, m, y, k;
  280.  
  281.   c = clip01(1 - color->c[0]);
  282.   m = clip01(1 - color->c[1]);
  283.   y = clip01(1 - color->c[2]);
  284.   k = c;
  285.   if (m < k) {
  286.     k = m;
  287.   }
  288.   if (y < k) {
  289.     k = y;
  290.   }
  291.   cmyk->c = c - k;
  292.   cmyk->m = m - k;
  293.   cmyk->y = y - k;
  294.   cmyk->k = k;
  295. }
  296.  
  297. //------------------------------------------------------------------------
  298. // GfxCalRGBColorSpace
  299. //------------------------------------------------------------------------
  300.  
  301. GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
  302.   whiteX = whiteY = whiteZ = 1;
  303.   blackX = blackY = blackZ = 0;
  304.   gammaR = gammaG = gammaB = 1;
  305.   mat[0] = 1; mat[1] = 0; mat[2] = 0;
  306.   mat[3] = 0; mat[4] = 1; mat[5] = 0;
  307.   mat[6] = 0; mat[7] = 0; mat[8] = 1;
  308. }
  309.  
  310. GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
  311. }
  312.  
  313. GfxColorSpace *GfxCalRGBColorSpace::copy() {
  314.   GfxCalRGBColorSpace *cs;
  315.   int i;
  316.  
  317.   cs = new GfxCalRGBColorSpace();
  318.   cs->whiteX = whiteX;
  319.   cs->whiteY = whiteY;
  320.   cs->whiteZ = whiteZ;
  321.   cs->blackX = blackX;
  322.   cs->blackY = blackY;
  323.   cs->blackZ = blackZ;
  324.   cs->gammaR = gammaR;
  325.   cs->gammaG = gammaG;
  326.   cs->gammaB = gammaB;
  327.   for (i = 0; i < 9; ++i) {
  328.     cs->mat[i] = mat[i];
  329.   }
  330.   return cs;
  331. }
  332.  
  333. GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
  334.   GfxCalRGBColorSpace *cs;
  335.   Object obj1, obj2, obj3;
  336.   int i;
  337.  
  338.   arr->get(1, &obj1);
  339.   if (!obj1.isDict()) {
  340.     error(-1, "Bad CalRGB color space");
  341.     obj1.free();
  342.     return NULL;
  343.   }
  344.   cs = new GfxCalRGBColorSpace();
  345.   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
  346.       obj2.arrayGetLength() == 3) {
  347.     obj2.arrayGet(0, &obj3);
  348.     cs->whiteX = obj3.getNum();
  349.     obj3.free();
  350.     obj2.arrayGet(1, &obj3);
  351.     cs->whiteY = obj3.getNum();
  352.     obj3.free();
  353.     obj2.arrayGet(2, &obj3);
  354.     cs->whiteZ = obj3.getNum();
  355.     obj3.free();
  356.   }
  357.   obj2.free();
  358.   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
  359.       obj2.arrayGetLength() == 3) {
  360.     obj2.arrayGet(0, &obj3);
  361.     cs->blackX = obj3.getNum();
  362.     obj3.free();
  363.     obj2.arrayGet(1, &obj3);
  364.     cs->blackY = obj3.getNum();
  365.     obj3.free();
  366.     obj2.arrayGet(2, &obj3);
  367.     cs->blackZ = obj3.getNum();
  368.     obj3.free();
  369.   }
  370.   obj2.free();
  371.   if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
  372.       obj2.arrayGetLength() == 3) {
  373.     obj2.arrayGet(0, &obj3);
  374.     cs->gammaR = obj3.getNum();
  375.     obj3.free();
  376.     obj2.arrayGet(1, &obj3);
  377.     cs->gammaG = obj3.getNum();
  378.     obj3.free();
  379.     obj2.arrayGet(2, &obj3);
  380.     cs->gammaB = obj3.getNum();
  381.     obj3.free();
  382.   }
  383.   obj2.free();
  384.   if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
  385.       obj2.arrayGetLength() == 9) {
  386.     for (i = 0; i < 9; ++i) {
  387.       obj2.arrayGet(i, &obj3);
  388.       cs->mat[i] = obj3.getNum();
  389.       obj3.free();
  390.     }
  391.   }
  392.   obj2.free();
  393.   obj1.free();
  394.   return cs;
  395. }
  396.  
  397. void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
  398.   *gray = clip01(0.299 * color->c[0] +
  399.                  0.587 * color->c[1] +
  400.                  0.114 * color->c[2]);
  401. }
  402.  
  403. void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  404.   rgb->r = clip01(color->c[0]);
  405.   rgb->g = clip01(color->c[1]);
  406.   rgb->b = clip01(color->c[2]);
  407. }
  408.  
  409. void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  410.   double c, m, y, k;
  411.  
  412.   c = clip01(1 - color->c[0]);
  413.   m = clip01(1 - color->c[1]);
  414.   y = clip01(1 - color->c[2]);
  415.   k = c;
  416.   if (m < k) {
  417.     k = m;
  418.   }
  419.   if (y < k) {
  420.     k = y;
  421.   }
  422.   cmyk->c = c - k;
  423.   cmyk->m = m - k;
  424.   cmyk->y = y - k;
  425.   cmyk->k = k;
  426. }
  427.  
  428. //------------------------------------------------------------------------
  429. // GfxDeviceCMYKColorSpace
  430. //------------------------------------------------------------------------
  431.  
  432. GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
  433. }
  434.  
  435. GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
  436. }
  437.  
  438. GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
  439.   return new GfxDeviceCMYKColorSpace();
  440. }
  441.  
  442. void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
  443.   *gray = clip01(1 - color->c[3]
  444.                  - 0.299 * color->c[0]
  445.                  - 0.587 * color->c[1]
  446.                  - 0.114 * color->c[2]);
  447. }
  448.  
  449. void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  450. //**** Colin Granville ****
  451. #ifdef ACORN
  452.   rgb->r = clip01(1 - (color->c[0] + color->c[3]));
  453.   rgb->g = clip01(1 - (color->c[1] + color->c[3]));
  454.   rgb->b = clip01(1 - (color->c[2] + color->c[3]));
  455.  
  456. #else
  457.   double c, m, y, aw, ac, am, ay, ar, ag, ab;
  458.  
  459.   c = clip01(color->c[0] + color->c[3]);
  460.   m = clip01(color->c[1] + color->c[3]);
  461.   y = clip01(color->c[2] + color->c[3]);
  462.   aw = (1-c) * (1-m) * (1-y);
  463.   ac = c * (1-m) * (1-y);
  464.   am = (1-c) * m * (1-y);
  465.   ay = (1-c) * (1-m) * y;
  466.   ar = (1-c) * m * y;
  467.   ag = c * (1-m) * y;
  468.   ab = c * m * (1-y);
  469.   rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
  470.   rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
  471.   rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
  472.                   0.4863*ab);
  473. #endif
  474. //**** end Colin Granville ****
  475. }
  476.  
  477. void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  478.   cmyk->c = clip01(color->c[0]);
  479.   cmyk->m = clip01(color->c[1]);
  480.   cmyk->y = clip01(color->c[2]);
  481.   cmyk->k = clip01(color->c[3]);
  482. }
  483.  
  484. //------------------------------------------------------------------------
  485. // GfxLabColorSpace
  486. //------------------------------------------------------------------------
  487.  
  488. // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
  489. // Language Reference, Third Edition.
  490. static double xyzrgb[3][3] = {
  491.   {  3.240449, -1.537136, -0.498531 },
  492.   { -0.969265,  1.876011,  0.041556 },
  493.   {  0.055643, -0.204026,  1.057229 }
  494. };
  495.  
  496. GfxLabColorSpace::GfxLabColorSpace() {
  497.   whiteX = whiteY = whiteZ = 1;
  498.   blackX = blackY = blackZ = 0;
  499.   aMin = bMin = -100;
  500.   aMax = bMax = 100;
  501. }
  502.  
  503. GfxLabColorSpace::~GfxLabColorSpace() {
  504. }
  505.  
  506. GfxColorSpace *GfxLabColorSpace::copy() {
  507.   GfxLabColorSpace *cs;
  508.  
  509.   cs = new GfxLabColorSpace();
  510.   cs->whiteX = whiteX;
  511.   cs->whiteY = whiteY;
  512.   cs->whiteZ = whiteZ;
  513.   cs->blackX = blackX;
  514.   cs->blackY = blackY;
  515.   cs->blackZ = blackZ;
  516.   cs->aMin = aMin;
  517.   cs->aMax = aMax;
  518.   cs->bMin = bMin;
  519.   cs->bMax = bMax;
  520.   cs->kr = kr;
  521.   cs->kg = kg;
  522.   cs->kb = kb;
  523.   return cs;
  524. }
  525.  
  526. GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
  527.   GfxLabColorSpace *cs;
  528.   Object obj1, obj2, obj3;
  529.  
  530.   arr->get(1, &obj1);
  531.   if (!obj1.isDict()) {
  532.     error(-1, "Bad Lab color space");
  533.     obj1.free();
  534.     return NULL;
  535.   }
  536.   cs = new GfxLabColorSpace();
  537.   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
  538.       obj2.arrayGetLength() == 3) {
  539.     obj2.arrayGet(0, &obj3);
  540.     cs->whiteX = obj3.getNum();
  541.     obj3.free();
  542.     obj2.arrayGet(1, &obj3);
  543.     cs->whiteY = obj3.getNum();
  544.     obj3.free();
  545.     obj2.arrayGet(2, &obj3);
  546.     cs->whiteZ = obj3.getNum();
  547.     obj3.free();
  548.   }
  549.   obj2.free();
  550.   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
  551.       obj2.arrayGetLength() == 3) {
  552.     obj2.arrayGet(0, &obj3);
  553.     cs->blackX = obj3.getNum();
  554.     obj3.free();
  555.     obj2.arrayGet(1, &obj3);
  556.     cs->blackY = obj3.getNum();
  557.     obj3.free();
  558.     obj2.arrayGet(2, &obj3);
  559.     cs->blackZ = obj3.getNum();
  560.     obj3.free();
  561.   }
  562.   obj2.free();
  563.   if (obj1.dictLookup("Range", &obj2)->isArray() &&
  564.       obj2.arrayGetLength() == 4) {
  565.     obj2.arrayGet(0, &obj3);
  566.     cs->aMin = obj3.getNum();
  567.     obj3.free();
  568.     obj2.arrayGet(1, &obj3);
  569.     cs->aMax = obj3.getNum();
  570.     obj3.free();
  571.     obj2.arrayGet(2, &obj3);
  572.     cs->bMin = obj3.getNum();
  573.     obj3.free();
  574.     obj2.arrayGet(3, &obj3);
  575.     cs->bMax = obj3.getNum();
  576.     obj3.free();
  577.   }
  578.   obj2.free();
  579.   obj1.free();
  580.  
  581.   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
  582.                 xyzrgb[0][1] * cs->whiteY +
  583.                 xyzrgb[0][2] * cs->whiteZ);
  584.   cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
  585.                 xyzrgb[1][1] * cs->whiteY +
  586.                 xyzrgb[1][2] * cs->whiteZ);
  587.   cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
  588.                 xyzrgb[2][1] * cs->whiteY +
  589.                 xyzrgb[2][2] * cs->whiteZ);
  590.  
  591.   return cs;
  592. }
  593.  
  594. void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
  595.   GfxRGB rgb;
  596.  
  597.   getRGB(color, &rgb);
  598.   *gray = clip01(0.299 * rgb.r +
  599.                  0.587 * rgb.g +
  600.                  0.114 * rgb.b);
  601. }
  602.  
  603. void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  604.   double X, Y, Z;
  605.   double t1, t2;
  606.   double r, g, b;
  607.  
  608.   // convert L*a*b* to CIE 1931 XYZ color space
  609.   t1 = (color->c[0] + 16) / 116;
  610.   t2 = t1 + color->c[1] / 500;
  611.   if (t2 >= (6.0 / 29.0)) {
  612.     X = t2 * t2 * t2;
  613.   } else {
  614.     X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
  615.   }
  616.   X *= whiteX;
  617.   if (t1 >= (6.0 / 29.0)) {
  618.     Y = t1 * t1 * t1;
  619.   } else {
  620.     Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
  621.   }
  622.   Y *= whiteY;
  623.   t2 = t1 - color->c[2] / 200;
  624.   if (t2 >= (6.0 / 29.0)) {
  625.     Z = t2 * t2 * t2;
  626.   } else {
  627.     Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
  628.   }
  629.   Z *= whiteZ;
  630.  
  631.   // convert XYZ to RGB, including gamut mapping and gamma correction
  632.   r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
  633.   g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
  634.   b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
  635.   rgb->r = pow(clip01(r * kr), 0.5);
  636.   rgb->g = pow(clip01(g * kg), 0.5);
  637.   rgb->b = pow(clip01(b * kb), 0.5);
  638. }
  639.  
  640. void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  641.   GfxRGB rgb;
  642.   double c, m, y, k;
  643.  
  644.   getRGB(color, &rgb);
  645.   c = clip01(1 - rgb.r);
  646.   m = clip01(1 - rgb.g);
  647.   y = clip01(1 - rgb.b);
  648.   k = c;
  649.   if (m < k) {
  650.     k = m;
  651.   }
  652.   if (y < k) {
  653.     k = y;
  654.   }
  655.   cmyk->c = c - k;
  656.   cmyk->m = m - k;
  657.   cmyk->y = y - k;
  658.   cmyk->k = k;
  659. }
  660.  
  661. void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
  662.                                         int maxImgPixel) {
  663.   decodeLow[0] = 0;
  664.   decodeRange[0] = 100;
  665.   decodeLow[1] = aMin;
  666.   decodeRange[1] = aMax - aMin;
  667.   decodeLow[2] = bMin;
  668.   decodeRange[2] = bMax - bMin;
  669. }
  670.  
  671. //------------------------------------------------------------------------
  672. // GfxICCBasedColorSpace
  673. //------------------------------------------------------------------------
  674.  
  675. GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
  676.                                              Ref *iccProfileStreamA) {
  677.   nComps = nCompsA;
  678.   alt = altA;
  679.   iccProfileStream = *iccProfileStreamA;
  680.   rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
  681.   rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
  682. }
  683.  
  684. GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
  685.   delete alt;
  686. }
  687.  
  688. GfxColorSpace *GfxICCBasedColorSpace::copy() {
  689.   GfxICCBasedColorSpace *cs;
  690.   int i;
  691.  
  692.   cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
  693.   for (i = 0; i < 4; ++i) {
  694.     cs->rangeMin[i] = rangeMin[i];
  695.     cs->rangeMax[i] = rangeMax[i];
  696.   }
  697.   return cs;
  698. }
  699.  
  700. GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
  701.   GfxICCBasedColorSpace *cs;
  702.   Ref iccProfileStreamA;
  703.   int nCompsA;
  704.   GfxColorSpace *altA;
  705.   Dict *dict;
  706.   Object obj1, obj2, obj3;
  707.   int i;
  708.  
  709.   arr->getNF(1, &obj1);
  710.   if (obj1.isRef()) {
  711.     iccProfileStreamA = obj1.getRef();
  712.   } else {
  713.     iccProfileStreamA.num = 0;
  714.     iccProfileStreamA.gen = 0;
  715.   }
  716.   obj1.free();
  717.   arr->get(1, &obj1);
  718.   if (!obj1.isStream()) {
  719.     error(-1, "Bad ICCBased color space (stream)");
  720.     obj1.free();
  721.     return NULL;
  722.   }
  723.   dict = obj1.streamGetDict();
  724.   if (!dict->lookup("N", &obj2)->isInt()) {
  725.     error(-1, "Bad ICCBased color space (N)");
  726.     obj2.free();
  727.     obj1.free();
  728.     return NULL;
  729.   }
  730.   nCompsA = obj2.getInt();
  731.   obj2.free();
  732.   if (dict->lookup("Alternate", &obj2)->isNull() ||
  733.       !(altA = GfxColorSpace::parse(&obj2))) {
  734.     switch (nCompsA) {
  735.     case 1:
  736.       altA = new GfxDeviceGrayColorSpace();
  737.       break;
  738.     case 3:
  739.       altA = new GfxDeviceRGBColorSpace();
  740.       break;
  741.     case 4:
  742.       altA = new GfxDeviceCMYKColorSpace();
  743.       break;
  744.     default:
  745.       error(-1, "Bad ICCBased color space - invalid N");
  746.       obj2.free();
  747.       obj1.free();
  748.       return NULL;
  749.     }
  750.   }
  751.   obj2.free();
  752.   cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
  753.   if (dict->lookup("Range", &obj2)->isArray() &&
  754.       obj2.arrayGetLength() == 2 * nCompsA) {
  755.     for (i = 0; i < nCompsA; ++i) {
  756.       obj2.arrayGet(2*i, &obj3);
  757.       cs->rangeMin[i] = obj3.getNum();
  758.       obj3.free();
  759.       obj2.arrayGet(2*i+1, &obj3);
  760.       cs->rangeMax[i] = obj3.getNum();
  761.       obj3.free();
  762.     }
  763.   }
  764.   obj2.free();
  765.   obj1.free();
  766.   return cs;
  767. }
  768.  
  769. void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
  770.   alt->getGray(color, gray);
  771. }
  772.  
  773. void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  774.   alt->getRGB(color, rgb);
  775. }
  776.  
  777. void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  778.   alt->getCMYK(color, cmyk);
  779. }
  780.  
  781. void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
  782.                                              double *decodeRange,
  783.                                              int maxImgPixel) {
  784.   int i;
  785.  
  786.   for (i = 0; i < nComps; ++i) {
  787.     decodeLow[i] = rangeMin[i];
  788.     decodeRange[i] = rangeMax[i] - rangeMin[i];
  789.   }
  790. }
  791.  
  792. //------------------------------------------------------------------------
  793. // GfxIndexedColorSpace
  794. //------------------------------------------------------------------------
  795.  
  796. GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
  797.                                            int indexHighA) {
  798.   base = baseA;
  799.   indexHigh = indexHighA;
  800.   lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
  801.                              sizeof(Guchar));
  802. }
  803.  
  804. GfxIndexedColorSpace::~GfxIndexedColorSpace() {
  805.   delete base;
  806.   gfree(lookup);
  807. }
  808.  
  809. GfxColorSpace *GfxIndexedColorSpace::copy() {
  810.   GfxIndexedColorSpace *cs;
  811.  
  812.   cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
  813.   memcpy(cs->lookup, lookup,
  814.          (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
  815.   return cs;
  816. }
  817.  
  818. GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
  819.   GfxIndexedColorSpace *cs;
  820.   GfxColorSpace *baseA;
  821.   int indexHighA;
  822.   Object obj1;
  823.   int x;
  824.   char *s;
  825.   int n, i, j;
  826.  
  827.   if (arr->getLength() != 4) {
  828.     error(-1, "Bad Indexed color space");
  829.     goto err1;
  830.   }
  831.   arr->get(1, &obj1);
  832.   if (!(baseA = GfxColorSpace::parse(&obj1))) {
  833.     error(-1, "Bad Indexed color space (base color space)");
  834.     goto err2;
  835.   }
  836.   obj1.free();
  837.   if (!arr->get(2, &obj1)->isInt()) {
  838.     error(-1, "Bad Indexed color space (hival)");
  839.     goto err2;
  840.   }
  841.   indexHighA = obj1.getInt();
  842.   obj1.free();
  843.   cs = new GfxIndexedColorSpace(baseA, indexHighA);
  844.   arr->get(3, &obj1);
  845.   n = baseA->getNComps();
  846.   if (obj1.isStream()) {
  847.     obj1.streamReset();
  848.     for (i = 0; i <= indexHighA; ++i) {
  849.       for (j = 0; j < n; ++j) {
  850.         if ((x = obj1.streamGetChar()) == EOF) {
  851.           error(-1, "Bad Indexed color space (lookup table stream too short)");
  852.           goto err3;
  853.         }
  854.         cs->lookup[i*n + j] = (Guchar)x;
  855.       }
  856.     }
  857.     obj1.streamClose();
  858.   } else if (obj1.isString()) {
  859.     if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
  860.       error(-1, "Bad Indexed color space (lookup table string too short)");
  861.       goto err3;
  862.     }
  863.     s = obj1.getString()->getCString();
  864.     for (i = 0; i <= indexHighA; ++i) {
  865.       for (j = 0; j < n; ++j) {
  866.         cs->lookup[i*n + j] = (Guchar)*s++;
  867.       }
  868.     }
  869.   } else {
  870.     error(-1, "Bad Indexed color space (lookup table)");
  871.     goto err3;
  872.   }
  873.   obj1.free();
  874.   return cs;
  875.  
  876.  err3:
  877.   delete cs;
  878.  err2:
  879.   obj1.free();
  880.  err1:
  881.   return NULL;
  882. }
  883.  
  884. GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
  885.                                                GfxColor *baseColor) {
  886.   Guchar *p;
  887.   double low[gfxColorMaxComps], range[gfxColorMaxComps];
  888.   int n, i;
  889.  
  890.   n = base->getNComps();
  891.   base->getDefaultRanges(low, range, indexHigh);
  892.   p = &lookup[(int)(color->c[0] + 0.5) * n];
  893.   for (i = 0; i < n; ++i) {
  894.     baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i];
  895.   }
  896.   return baseColor;
  897. }
  898.  
  899. void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
  900.   GfxColor color2;
  901.  
  902.   base->getGray(mapColorToBase(color, &color2), gray);
  903. }
  904.  
  905. void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  906.   GfxColor color2;
  907.  
  908.   base->getRGB(mapColorToBase(color, &color2), rgb);
  909. }
  910.  
  911. void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  912.   GfxColor color2;
  913.  
  914.   base->getCMYK(mapColorToBase(color, &color2), cmyk);
  915. }
  916.  
  917. void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
  918.                                             double *decodeRange,
  919.                                             int maxImgPixel) {
  920.   decodeLow[0] = 0;
  921.   decodeRange[0] = maxImgPixel;
  922. }
  923.  
  924. //------------------------------------------------------------------------
  925. // GfxSeparationColorSpace
  926. //------------------------------------------------------------------------
  927.  
  928. GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
  929.                                                  GfxColorSpace *altA,
  930.                                                  Function *funcA) {
  931.   name = nameA;
  932.   alt = altA;
  933.   func = funcA;
  934. }
  935.  
  936. GfxSeparationColorSpace::~GfxSeparationColorSpace() {
  937.   delete name;
  938.   delete alt;
  939.   delete func;
  940. }
  941.  
  942. GfxColorSpace *GfxSeparationColorSpace::copy() {
  943.   return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
  944. }
  945.  
  946. //~ handle the 'All' and 'None' colorants
  947. GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
  948.   GfxSeparationColorSpace *cs;
  949.   GString *nameA;
  950.   GfxColorSpace *altA;
  951.   Function *funcA;
  952.   Object obj1;
  953.  
  954.   if (arr->getLength() != 4) {
  955.     error(-1, "Bad Separation color space");
  956.     goto err1;
  957.   }
  958.   if (!arr->get(1, &obj1)->isName()) {
  959.     error(-1, "Bad Separation color space (name)");
  960.     goto err2;
  961.   }
  962.   nameA = new GString(obj1.getName());
  963.   obj1.free();
  964.   arr->get(2, &obj1);
  965.   if (!(altA = GfxColorSpace::parse(&obj1))) {
  966.     error(-1, "Bad Separation color space (alternate color space)");
  967.     goto err3;
  968.   }
  969.   obj1.free();
  970.   arr->get(3, &obj1);
  971.   if (!(funcA = Function::parse(&obj1))) {
  972.     goto err4;
  973.   }
  974.   obj1.free();
  975.   cs = new GfxSeparationColorSpace(nameA, altA, funcA);
  976.   return cs;
  977.  
  978.  err4:
  979.   delete altA;
  980.  err3:
  981.   delete nameA;
  982.  err2:
  983.   obj1.free();
  984.  err1:
  985.   return NULL;
  986. }
  987.  
  988. void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
  989.   GfxColor color2;
  990.  
  991.   func->transform(color->c, color2.c);
  992.   alt->getGray(&color2, gray);
  993. }
  994.  
  995. void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  996.   GfxColor color2;
  997.  
  998.   func->transform(color->c, color2.c);
  999.   alt->getRGB(&color2, rgb);
  1000. }
  1001.  
  1002. void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  1003.   GfxColor color2;
  1004.  
  1005.   func->transform(color->c, color2.c);
  1006.   alt->getCMYK(&color2, cmyk);
  1007. }
  1008.  
  1009. //------------------------------------------------------------------------
  1010. // GfxDeviceNColorSpace
  1011. //------------------------------------------------------------------------
  1012.  
  1013. GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
  1014.                                            GfxColorSpace *altA,
  1015.                                            Function *funcA) {
  1016.   nComps = nCompsA;
  1017.   alt = altA;
  1018.   func = funcA;
  1019. }
  1020.  
  1021. GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
  1022.   int i;
  1023.  
  1024.   for (i = 0; i < nComps; ++i) {
  1025.     delete names[i];
  1026.   }
  1027.   delete alt;
  1028.   delete func;
  1029. }
  1030.  
  1031. GfxColorSpace *GfxDeviceNColorSpace::copy() {
  1032.   GfxDeviceNColorSpace *cs;
  1033.   int i;
  1034.  
  1035.   cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
  1036.   for (i = 0; i < nComps; ++i) {
  1037.     cs->names[i] = names[i]->copy();
  1038.   }
  1039.   return cs;
  1040. }
  1041.  
  1042. //~ handle the 'None' colorant
  1043. GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
  1044.   GfxDeviceNColorSpace *cs;
  1045.   int nCompsA;
  1046.   GString *namesA[gfxColorMaxComps];
  1047.   GfxColorSpace *altA;
  1048.   Function *funcA;
  1049.   Object obj1, obj2;
  1050.   int i;
  1051.  
  1052.   if (arr->getLength() != 4 && arr->getLength() != 5) {
  1053.     error(-1, "Bad DeviceN color space");
  1054.     goto err1;
  1055.   }
  1056.   if (!arr->get(1, &obj1)->isArray()) {
  1057.     error(-1, "Bad DeviceN color space (names)");
  1058.     goto err2;
  1059.   }
  1060.   nCompsA = obj1.arrayGetLength();
  1061.   for (i = 0; i < nCompsA; ++i) {
  1062.     if (!obj1.arrayGet(i, &obj2)->isName()) {
  1063.       error(-1, "Bad DeviceN color space (names)");
  1064.       obj2.free();
  1065.       goto err2;
  1066.     }
  1067.     namesA[i] = new GString(obj2.getName());
  1068.     obj2.free();
  1069.   }
  1070.   obj1.free();
  1071.   arr->get(2, &obj1);
  1072.   if (!(altA = GfxColorSpace::parse(&obj1))) {
  1073.     error(-1, "Bad DeviceN color space (alternate color space)");
  1074.     goto err3;
  1075.   }
  1076.   obj1.free();
  1077.   arr->get(3, &obj1);
  1078.   if (!(funcA = Function::parse(&obj1))) {
  1079.     goto err4;
  1080.   }
  1081.   obj1.free();
  1082.   cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
  1083.   for (i = 0; i < nCompsA; ++i) {
  1084.     cs->names[i] = namesA[i];
  1085.   }
  1086.   return cs;
  1087.  
  1088.  err4:
  1089.   delete altA;
  1090.  err3:
  1091.   for (i = 0; i < nCompsA; ++i) {
  1092.     delete namesA[i];
  1093.   }
  1094.  err2:
  1095.   obj1.free();
  1096.  err1:
  1097.   return NULL;
  1098. }
  1099.  
  1100. void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
  1101.   GfxColor color2;
  1102.  
  1103.   func->transform(color->c, color2.c);
  1104.   alt->getGray(&color2, gray);
  1105. }
  1106.  
  1107. void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  1108.   GfxColor color2;
  1109.  
  1110.   func->transform(color->c, color2.c);
  1111.   alt->getRGB(&color2, rgb);
  1112. }
  1113.  
  1114. void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  1115.   GfxColor color2;
  1116.  
  1117.   func->transform(color->c, color2.c);
  1118.   alt->getCMYK(&color2, cmyk);
  1119. }
  1120.  
  1121. //------------------------------------------------------------------------
  1122. // GfxPatternColorSpace
  1123. //------------------------------------------------------------------------
  1124.  
  1125. GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
  1126.   under = underA;
  1127. }
  1128.  
  1129. GfxPatternColorSpace::~GfxPatternColorSpace() {
  1130.   if (under) {
  1131.     delete under;
  1132.   }
  1133. }
  1134.  
  1135. GfxColorSpace *GfxPatternColorSpace::copy() {
  1136.   return new GfxPatternColorSpace(under ? under->copy() :
  1137.                                           (GfxColorSpace *)NULL);
  1138. }
  1139.  
  1140. GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
  1141.   GfxPatternColorSpace *cs;
  1142.   GfxColorSpace *underA;
  1143.   Object obj1;
  1144.  
  1145.   if (arr->getLength() != 1 && arr->getLength() != 2) {
  1146.     error(-1, "Bad Pattern color space");
  1147.     return NULL;
  1148.   }
  1149.   underA = NULL;
  1150.   if (arr->getLength() == 2) {
  1151.     arr->get(1, &obj1);
  1152.     if (!(underA = GfxColorSpace::parse(&obj1))) {
  1153.       error(-1, "Bad Pattern color space (underlying color space)");
  1154.       obj1.free();
  1155.       return NULL;
  1156.     }
  1157.     obj1.free();
  1158.   }
  1159.   cs = new GfxPatternColorSpace(underA);
  1160.   return cs;
  1161. }
  1162.  
  1163. void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
  1164.   *gray = 0;
  1165. }
  1166.  
  1167. void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
  1168.   rgb->r = rgb->g = rgb->b = 0;
  1169. }
  1170.  
  1171. void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
  1172.   cmyk->c = cmyk->m = cmyk->y = 0;
  1173.   cmyk->k = 1;
  1174. }
  1175.  
  1176. //------------------------------------------------------------------------
  1177. // Pattern
  1178. //------------------------------------------------------------------------
  1179.  
  1180. GfxPattern::GfxPattern(int typeA) {
  1181.   type = typeA;
  1182. }
  1183.  
  1184. GfxPattern::~GfxPattern() {
  1185. }
  1186.  
  1187. GfxPattern *GfxPattern::parse(Object *obj) {
  1188.   GfxPattern *pattern;
  1189.   Dict *dict;
  1190.   Object obj1;
  1191.  
  1192.   pattern = NULL;
  1193.   if (obj->isStream()) {
  1194.     dict = obj->streamGetDict();
  1195.     dict->lookup("PatternType", &obj1);
  1196.     if (obj1.isInt() && obj1.getInt() == 1) {
  1197.       pattern = new GfxTilingPattern(dict, obj);
  1198.     }
  1199.     obj1.free();
  1200.   }
  1201.   return pattern;
  1202. }
  1203.  
  1204. //------------------------------------------------------------------------
  1205. // GfxTilingPattern
  1206. //------------------------------------------------------------------------
  1207.  
  1208. GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
  1209.   GfxPattern(1)
  1210. {
  1211.   Object obj1, obj2;
  1212.   int i;
  1213.  
  1214.   if (streamDict->lookup("PaintType", &obj1)->isInt()) {
  1215.     paintType = obj1.getInt();
  1216.   } else {
  1217.     paintType = 1;
  1218.     error(-1, "Invalid or missing PaintType in pattern");
  1219.   }
  1220.   obj1.free();
  1221.   if (streamDict->lookup("TilingType", &obj1)->isInt()) {
  1222.     tilingType = obj1.getInt();
  1223.   } else {
  1224.     tilingType = 1;
  1225.     error(-1, "Invalid or missing TilingType in pattern");
  1226.   }
  1227.   obj1.free();
  1228.   bbox[0] = bbox[1] = 0;
  1229.   bbox[2] = bbox[3] = 1;
  1230.   if (streamDict->lookup("BBox", &obj1)->isArray() &&
  1231.       obj1.arrayGetLength() == 4) {
  1232.     for (i = 0; i < 4; ++i) {
  1233.       if (obj1.arrayGet(i, &obj2)->isNum()) {
  1234.         bbox[i] = obj2.getNum();
  1235.       }
  1236.       obj2.free();
  1237.     }
  1238.   } else {
  1239.     error(-1, "Invalid or missing BBox in pattern");
  1240.   }
  1241.   obj1.free();
  1242.   if (streamDict->lookup("XStep", &obj1)->isNum()) {
  1243.     xStep = obj1.getNum();
  1244.   } else {
  1245.     xStep = 1;
  1246.     error(-1, "Invalid or missing XStep in pattern");
  1247.   }
  1248.   obj1.free();
  1249.   if (streamDict->lookup("YStep", &obj1)->isNum()) {
  1250.     yStep = obj1.getNum();
  1251.   } else {
  1252.     yStep = 1;
  1253.     error(-1, "Invalid or missing YStep in pattern");
  1254.   }
  1255.   obj1.free();
  1256.   if (!streamDict->lookup("Resources", &resDict)->isDict()) {
  1257.     resDict.free();
  1258.     resDict.initNull();
  1259.     error(-1, "Invalid or missing Resources in pattern");
  1260.   }
  1261.   matrix[0] = 1; matrix[1] = 0;
  1262.   matrix[2] = 0; matrix[3] = 1;
  1263.   matrix[4] = 0; matrix[5] = 0;
  1264.   if (streamDict->lookup("Matrix", &obj1)->isArray() &&
  1265.       obj1.arrayGetLength() == 6) {
  1266.     for (i = 0; i < 6; ++i) {
  1267.       if (obj1.arrayGet(i, &obj2)->isNum()) {
  1268.         matrix[i] = obj2.getNum();
  1269.       }
  1270.       obj2.free();
  1271.     }
  1272.   }
  1273.   obj1.free();
  1274.   stream->copy(&contentStream);
  1275. }
  1276.  
  1277. GfxTilingPattern::~GfxTilingPattern() {
  1278.   resDict.free();
  1279.   contentStream.free();
  1280. }
  1281.  
  1282. GfxPattern *GfxTilingPattern::copy() {
  1283.   return new GfxTilingPattern(this);
  1284. }
  1285.  
  1286. GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
  1287.   GfxPattern(1)
  1288. {
  1289.   memcpy(this, pat, sizeof(GfxTilingPattern));
  1290.   pat->resDict.copy(&resDict);
  1291.   pat->contentStream.copy(&contentStream);
  1292. }
  1293.  
  1294. //------------------------------------------------------------------------
  1295. // GfxShading
  1296. //------------------------------------------------------------------------
  1297.  
  1298. GfxShading::GfxShading() {
  1299. }
  1300.  
  1301. GfxShading::~GfxShading() {
  1302.   delete colorSpace;
  1303. }
  1304.  
  1305. GfxShading *GfxShading::parse(Object *obj) {
  1306.   GfxShading *shading;
  1307.   int typeA;
  1308.   GfxColorSpace *colorSpaceA;
  1309.   GfxColor backgroundA;
  1310.   GBool hasBackgroundA;
  1311.   double xMinA, yMinA, xMaxA, yMaxA;
  1312.   GBool hasBBoxA;
  1313.   Object obj1, obj2;
  1314.   int i;
  1315.  
  1316.   shading = NULL;
  1317.   if (obj->isDict()) {
  1318.  
  1319.     if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
  1320.       error(-1, "Invalid ShadingType in shading dictionary");
  1321.       obj1.free();
  1322.       goto err1;
  1323.     }
  1324.     typeA = obj1.getInt();
  1325.     obj1.free();
  1326.  
  1327.     obj->dictLookup("ColorSpace", &obj1);
  1328.     if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
  1329.       error(-1, "Bad color space in shading dictionary");
  1330.       obj1.free();
  1331.       goto err1;
  1332.     }
  1333.     obj1.free();
  1334.  
  1335.     for (i = 0; i < gfxColorMaxComps; ++i) {
  1336.       backgroundA.c[i] = 0;
  1337.     }
  1338.     hasBackgroundA = gFalse;
  1339.     if (obj->dictLookup("Background", &obj1)->isArray()) {
  1340.       if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
  1341.         hasBackgroundA = gTrue;
  1342.         for (i = 0; i < colorSpaceA->getNComps(); ++i) {
  1343.           backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
  1344.           obj2.free();
  1345.         }
  1346.       } else {
  1347.         error(-1, "Bad Background in shading dictionary");
  1348.       }
  1349.     }
  1350.     obj1.free();
  1351.  
  1352.     xMinA = yMinA = xMaxA = yMaxA = 0;
  1353.     hasBBoxA = gFalse;
  1354.     if (obj->dictLookup("BBox", &obj1)->isArray()) {
  1355.       if (obj1.arrayGetLength() == 4) {
  1356.         hasBBoxA = gTrue;
  1357.         xMinA = obj1.arrayGet(0, &obj2)->getNum();
  1358.         obj2.free();
  1359.         yMinA = obj1.arrayGet(1, &obj2)->getNum();
  1360.         obj2.free();
  1361.         xMaxA = obj1.arrayGet(2, &obj2)->getNum();
  1362.         obj2.free();
  1363.         yMaxA = obj1.arrayGet(3, &obj2)->getNum();
  1364.         obj2.free();
  1365.       } else {
  1366.         error(-1, "Bad BBox in shading dictionary");
  1367.       }
  1368.     }
  1369.     obj1.free();
  1370.  
  1371.     switch (typeA) {
  1372.     case 2:
  1373.       shading = GfxAxialShading::parse(obj->getDict());
  1374.       break;
  1375.     case 3:
  1376.       shading = GfxRadialShading::parse(obj->getDict());
  1377.       break;
  1378.     default:
  1379.       error(-1, "Unimplemented shading type %d", typeA);
  1380.       goto err1;
  1381.     }
  1382.  
  1383.     if (shading) {
  1384.       shading->type = typeA;
  1385.       shading->colorSpace = colorSpaceA;
  1386.       shading->background = backgroundA;
  1387.       shading->hasBackground = hasBackgroundA;
  1388.       shading->xMin = xMinA;
  1389.       shading->yMin = yMinA;
  1390.       shading->xMax = xMaxA;
  1391.       shading->yMax = yMaxA;
  1392.       shading->hasBBox = hasBBoxA;
  1393.     } else {
  1394.       delete colorSpaceA;
  1395.     }
  1396.   }
  1397.  
  1398.   return shading;
  1399.  
  1400.  err1:
  1401.   return NULL;
  1402. }
  1403.  
  1404. //------------------------------------------------------------------------
  1405. // GfxAxialShading
  1406. //------------------------------------------------------------------------
  1407.  
  1408. GfxAxialShading::GfxAxialShading(double x0A, double y0A,
  1409.                                  double x1A, double y1A,
  1410.                                  double t0A, double t1A,
  1411.                                  Function **funcsA, int nFuncsA,
  1412.                                  GBool extend0A, GBool extend1A) {
  1413.   int i;
  1414.  
  1415.   x0 = x0A;
  1416.   y0 = y0A;
  1417.   x1 = x1A;
  1418.   y1 = y1A;
  1419.   t0 = t0A;
  1420.   t1 = t1A;
  1421.   nFuncs = nFuncsA;
  1422.   for (i = 0; i < nFuncs; ++i) {
  1423.     funcs[i] = funcsA[i];
  1424.   }
  1425.   extend0 = extend0A;
  1426.   extend1 = extend1A;
  1427. }
  1428.  
  1429. GfxAxialShading::~GfxAxialShading() {
  1430.   int i;
  1431.  
  1432.   for (i = 0; i < nFuncs; ++i) {
  1433.     delete funcs[i];
  1434.   }
  1435. }
  1436.  
  1437. GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
  1438.   double x0A, y0A, x1A, y1A;
  1439.   double t0A, t1A;
  1440.   Function *funcsA[gfxColorMaxComps];
  1441.   int nFuncsA;
  1442.   GBool extend0A, extend1A;
  1443.   Object obj1, obj2;
  1444.   int i;
  1445.  
  1446.   x0A = y0A = x1A = y1A = 0;
  1447.   if (dict->lookup("Coords", &obj1)->isArray() &&
  1448.       obj1.arrayGetLength() == 4) {
  1449.     x0A = obj1.arrayGet(0, &obj2)->getNum();
  1450.     obj2.free();
  1451.     y0A = obj1.arrayGet(1, &obj2)->getNum();
  1452.     obj2.free();
  1453.     x1A = obj1.arrayGet(2, &obj2)->getNum();
  1454.     obj2.free();
  1455.     y1A = obj1.arrayGet(3, &obj2)->getNum();
  1456.     obj2.free();
  1457.   } else {
  1458.     error(-1, "Missing or invalid Coords in shading dictionary");
  1459.     goto err1;
  1460.   }
  1461.   obj1.free();
  1462.  
  1463.   t0A = 0;
  1464.   t1A = 1;
  1465.   if (dict->lookup("Domain", &obj1)->isArray() &&
  1466.       obj1.arrayGetLength() == 2) {
  1467.     t0A = obj1.arrayGet(0, &obj2)->getNum();
  1468.     obj2.free();
  1469.     t1A = obj1.arrayGet(1, &obj2)->getNum();
  1470.     obj2.free();
  1471.   }
  1472.   obj1.free();
  1473.  
  1474.   dict->lookup("Function", &obj1);
  1475.   if (obj1.isArray()) {
  1476.     nFuncsA = obj1.arrayGetLength();
  1477.     for (i = 0; i < nFuncsA; ++i) {
  1478.       obj1.arrayGet(i, &obj2);
  1479.       if (!(funcsA[i] = Function::parse(&obj2))) {
  1480.         obj1.free();
  1481.         obj2.free();
  1482.         goto err1;
  1483.       }
  1484.       obj2.free();
  1485.     }
  1486.   } else {
  1487.     nFuncsA = 1;
  1488.     if (!(funcsA[0] = Function::parse(&obj1))) {
  1489.       obj1.free();
  1490.       goto err1;
  1491.     }
  1492.   }
  1493.   obj1.free();
  1494.  
  1495.   extend0A = extend1A = gFalse;
  1496.   if (dict->lookup("Extend", &obj1)->isArray() &&
  1497.       obj1.arrayGetLength() == 2) {
  1498.     extend0A = obj1.arrayGet(0, &obj2)->getBool();
  1499.     obj2.free();
  1500.     extend1A = obj1.arrayGet(1, &obj2)->getBool();
  1501.     obj2.free();
  1502.   }
  1503.   obj1.free();
  1504.  
  1505.   return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
  1506.                              funcsA, nFuncsA, extend0A, extend1A);
  1507.  
  1508.  err1:
  1509.   return NULL;
  1510. }
  1511.  
  1512. void GfxAxialShading::getColor(double t, GfxColor *color) {
  1513.   int i;
  1514.  
  1515.   for (i = 0; i < nFuncs; ++i) {
  1516.     funcs[i]->transform(&t, &color->c[i]);
  1517.   }
  1518. }
  1519.  
  1520. //------------------------------------------------------------------------
  1521. // GfxRadialShading
  1522. //------------------------------------------------------------------------
  1523.  
  1524. GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
  1525.                                    double x1A, double y1A, double r1A,
  1526.                                    double t0A, double t1A,
  1527.                                    Function **funcsA, int nFuncsA,
  1528.                                    GBool extend0A, GBool extend1A) {
  1529.   int i;
  1530.  
  1531.   x0 = x0A;
  1532.   y0 = y0A;
  1533.   r0 = r0A;
  1534.   x1 = x1A;
  1535.   y1 = y1A;
  1536.   r1 = r1A;
  1537.   t0 = t0A;
  1538.   t1 = t1A;
  1539.   nFuncs = nFuncsA;
  1540.   for (i = 0; i < nFuncs; ++i) {
  1541.     funcs[i] = funcsA[i];
  1542.   }
  1543.   extend0 = extend0A;
  1544.   extend1 = extend1A;
  1545. }
  1546.  
  1547. GfxRadialShading::~GfxRadialShading() {
  1548.   int i;
  1549.  
  1550.   for (i = 0; i < nFuncs; ++i) {
  1551.     delete funcs[i];
  1552.   }
  1553. }
  1554.  
  1555. GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
  1556.   double x0A, y0A, r0A, x1A, y1A, r1A;
  1557.   double t0A, t1A;
  1558.   Function *funcsA[gfxColorMaxComps];
  1559.   int nFuncsA;
  1560.   GBool extend0A, extend1A;
  1561.   Object obj1, obj2;
  1562.   int i;
  1563.  
  1564.   x0A = y0A = r0A = x1A = y1A = r1A = 0;
  1565.   if (dict->lookup("Coords", &obj1)->isArray() &&
  1566.       obj1.arrayGetLength() == 6) {
  1567.     x0A = obj1.arrayGet(0, &obj2)->getNum();
  1568.     obj2.free();
  1569.     y0A = obj1.arrayGet(1, &obj2)->getNum();
  1570.     obj2.free();
  1571.     r0A = obj1.arrayGet(2, &obj2)->getNum();
  1572.     obj2.free();
  1573.     x1A = obj1.arrayGet(3, &obj2)->getNum();
  1574.     obj2.free();
  1575.     y1A = obj1.arrayGet(4, &obj2)->getNum();
  1576.     obj2.free();
  1577.     r1A = obj1.arrayGet(5, &obj2)->getNum();
  1578.     obj2.free();
  1579.   } else {
  1580.     error(-1, "Missing or invalid Coords in shading dictionary");
  1581.     goto err1;
  1582.   }
  1583.   obj1.free();
  1584.  
  1585.   t0A = 0;
  1586.   t1A = 1;
  1587.   if (dict->lookup("Domain", &obj1)->isArray() &&
  1588.       obj1.arrayGetLength() == 2) {
  1589.     t0A = obj1.arrayGet(0, &obj2)->getNum();
  1590.     obj2.free();
  1591.     t1A = obj1.arrayGet(1, &obj2)->getNum();
  1592.     obj2.free();
  1593.   }
  1594.   obj1.free();
  1595.  
  1596.   dict->lookup("Function", &obj1);
  1597.   if (obj1.isArray()) {
  1598.     nFuncsA = obj1.arrayGetLength();
  1599.     for (i = 0; i < nFuncsA; ++i) {
  1600.       obj1.arrayGet(i, &obj2);
  1601.       if (!(funcsA[i] = Function::parse(&obj2))) {
  1602.         obj1.free();
  1603.         obj2.free();
  1604.         goto err1;
  1605.       }
  1606.       obj2.free();
  1607.     }
  1608.   } else {
  1609.     nFuncsA = 1;
  1610.     if (!(funcsA[0] = Function::parse(&obj1))) {
  1611.       obj1.free();
  1612.       goto err1;
  1613.     }
  1614.   }
  1615.   obj1.free();
  1616.  
  1617.   extend0A = extend1A = gFalse;
  1618.   if (dict->lookup("Extend", &obj1)->isArray() &&
  1619.       obj1.arrayGetLength() == 2) {
  1620.     extend0A = obj1.arrayGet(0, &obj2)->getBool();
  1621.     obj2.free();
  1622.     extend1A = obj1.arrayGet(1, &obj2)->getBool();
  1623.     obj2.free();
  1624.   }
  1625.   obj1.free();
  1626.  
  1627.   return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
  1628.                               funcsA, nFuncsA, extend0A, extend1A);
  1629.  
  1630.  err1:
  1631.   return NULL;
  1632. }
  1633.  
  1634. void GfxRadialShading::getColor(double t, GfxColor *color) {
  1635.   int i;
  1636.  
  1637.   for (i = 0; i < nFuncs; ++i) {
  1638.     funcs[i]->transform(&t, &color->c[i]);
  1639.   }
  1640. }
  1641.  
  1642. //------------------------------------------------------------------------
  1643. // GfxImageColorMap
  1644. //------------------------------------------------------------------------
  1645.  
  1646. GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
  1647.                                    GfxColorSpace *colorSpaceA) {
  1648.   GfxIndexedColorSpace *indexedCS;
  1649.   GfxSeparationColorSpace *sepCS;
  1650.   int maxPixel, indexHigh;
  1651.   Guchar *lookup2;
  1652.   Function *sepFunc;
  1653.   Object obj;
  1654.   double x[gfxColorMaxComps];
  1655.   double y[gfxColorMaxComps];
  1656.   int i, j, k;
  1657.  
  1658.   ok = gTrue;
  1659.  
  1660.   // bits per component and color space
  1661.   bits = bitsA;
  1662.   maxPixel = (1 << bits) - 1;
  1663.   colorSpace = colorSpaceA;
  1664.  
  1665.   // get decode map
  1666.   if (decode->isNull()) {
  1667.     nComps = colorSpace->getNComps();
  1668.     colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
  1669.   } else if (decode->isArray()) {
  1670.     nComps = decode->arrayGetLength() / 2;
  1671.     if (nComps != colorSpace->getNComps()) {
  1672.       goto err1;
  1673.     }
  1674.     for (i = 0; i < nComps; ++i) {
  1675.       decode->arrayGet(2*i, &obj);
  1676.       if (!obj.isNum()) {
  1677.         goto err2;
  1678.       }
  1679.       decodeLow[i] = obj.getNum();
  1680.       obj.free();
  1681.       decode->arrayGet(2*i+1, &obj);
  1682.       if (!obj.isNum()) {
  1683.         goto err2;
  1684.       }
  1685.       decodeRange[i] = obj.getNum() - decodeLow[i];
  1686.       obj.free();
  1687.     }
  1688.   } else {
  1689.     goto err1;
  1690.   }
  1691.  
  1692.   // Construct a lookup table -- this stores pre-computed decoded
  1693.   // values for each component, i.e., the result of applying the
  1694.   // decode mapping to each possible image pixel component value.
  1695.   //
  1696.   // Optimization: for Indexed and Separation color spaces (which have
  1697.   // only one component), we store color values in the lookup table
  1698.   // rather than component values.
  1699.   colorSpace2 = NULL;
  1700.   nComps2 = 0;
  1701.   if (colorSpace->getMode() == csIndexed) {
  1702.     // Note that indexHigh may not be the same as maxPixel --
  1703.     // Distiller will remove unused palette entries, resulting in
  1704.     // indexHigh < maxPixel.
  1705.     indexedCS = (GfxIndexedColorSpace *)colorSpace;
  1706.     colorSpace2 = indexedCS->getBase();
  1707.     indexHigh = indexedCS->getIndexHigh();
  1708.     nComps2 = colorSpace2->getNComps();
  1709.     lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
  1710.     lookup2 = indexedCS->getLookup();
  1711.     colorSpace2->getDefaultRanges(x, y, indexHigh);
  1712.     for (i = 0; i <= indexHigh; ++i) {
  1713.       j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
  1714.       for (k = 0; k < nComps2; ++k) {
  1715.         lookup[j*nComps2 + k] = x[k] + (lookup2[i*nComps2 + k] / 255.0) * y[k];
  1716.       }
  1717.     }
  1718.   } else if (colorSpace->getMode() == csSeparation) {
  1719.     sepCS = (GfxSeparationColorSpace *)colorSpace;
  1720.     colorSpace2 = sepCS->getAlt();
  1721.     nComps2 = colorSpace2->getNComps();
  1722.     lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
  1723.     sepFunc = sepCS->getFunc();
  1724.     for (i = 0; i <= maxPixel; ++i) {
  1725.       x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
  1726.       sepFunc->transform(x, y);
  1727.       for (k = 0; k < nComps2; ++k) {
  1728.         lookup[i*nComps2 + k] = y[k];
  1729.       }
  1730.     }
  1731.   } else {
  1732.     lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
  1733.     for (i = 0; i <= maxPixel; ++i) {
  1734.       for (k = 0; k < nComps; ++k) {
  1735.         lookup[i*nComps + k] = decodeLow[k] +
  1736.                                  (i * decodeRange[k]) / maxPixel;
  1737.       }
  1738.     }
  1739.   }
  1740.  
  1741.   return;
  1742.  
  1743.  err2:
  1744.   obj.free();
  1745.  err1:
  1746.   ok = gFalse;
  1747. }
  1748.  
  1749. GfxImageColorMap::~GfxImageColorMap() {
  1750.   delete colorSpace;
  1751.   gfree(lookup);
  1752. }
  1753.  
  1754. void GfxImageColorMap::getGray(Guchar *x, double *gray) {
  1755.   GfxColor color;
  1756.   double *p;
  1757.   int i;
  1758.  
  1759.   if (colorSpace2) {
  1760.     p = &lookup[x[0] * nComps2];
  1761.     for (i = 0; i < nComps2; ++i) {
  1762.       color.c[i] = *p++;
  1763.     }
  1764.     colorSpace2->getGray(&color, gray);
  1765.   } else {
  1766.     for (i = 0; i < nComps; ++i) {
  1767.       color.c[i] = lookup[x[i] * nComps + i];
  1768.     }
  1769.     colorSpace->getGray(&color, gray);
  1770.   }
  1771. }
  1772.  
  1773. void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
  1774.   GfxColor color;
  1775.   double *p;
  1776.   int i;
  1777.  
  1778.   if (colorSpace2) {
  1779.     p = &lookup[x[0] * nComps2];
  1780.     for (i = 0; i < nComps2; ++i) {
  1781.       color.c[i] = *p++;
  1782.     }
  1783.     colorSpace2->getRGB(&color, rgb);
  1784.   } else {
  1785.     for (i = 0; i < nComps; ++i) {
  1786.       color.c[i] = lookup[x[i] * nComps + i];
  1787.     }
  1788.     colorSpace->getRGB(&color, rgb);
  1789.   }
  1790. }
  1791.  
  1792. void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
  1793.   GfxColor color;
  1794.   double *p;
  1795.   int i;
  1796.  
  1797.   if (colorSpace2) {
  1798.     p = &lookup[x[0] * nComps2];
  1799.     for (i = 0; i < nComps2; ++i) {
  1800.       color.c[i] = *p++;
  1801.     }
  1802.     colorSpace2->getCMYK(&color, cmyk);
  1803.   } else {
  1804.     for (i = 0; i < nComps; ++i) {
  1805.       color.c[i] = lookup[x[i] * nComps + i];
  1806.     }
  1807.     colorSpace->getCMYK(&color, cmyk);
  1808.   }
  1809. }
  1810.  
  1811. void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
  1812.   int maxPixel, i;
  1813.  
  1814.   maxPixel = (1 << bits) - 1;
  1815.   for (i = 0; i < nComps; ++i) {
  1816.     color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel;
  1817.   }
  1818. }
  1819.  
  1820. //------------------------------------------------------------------------
  1821. // GfxSubpath and GfxPath
  1822. //------------------------------------------------------------------------
  1823.  
  1824. GfxSubpath::GfxSubpath(double x1, double y1) {
  1825.   size = 16;
  1826.   x = (double *)gmalloc(size * sizeof(double));
  1827.   y = (double *)gmalloc(size * sizeof(double));
  1828.   curve = (GBool *)gmalloc(size * sizeof(GBool));
  1829.   n = 1;
  1830.   x[0] = x1;
  1831.   y[0] = y1;
  1832.   curve[0] = gFalse;
  1833.   closed = gFalse;
  1834. }
  1835.  
  1836. GfxSubpath::~GfxSubpath() {
  1837.   gfree(x);
  1838.   gfree(y);
  1839.   gfree(curve);
  1840. }
  1841.  
  1842. // Used for copy().
  1843. GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
  1844.   size = subpath->size;
  1845.   n = subpath->n;
  1846.   x = (double *)gmalloc(size * sizeof(double));
  1847.   y = (double *)gmalloc(size * sizeof(double));
  1848.   curve = (GBool *)gmalloc(size * sizeof(GBool));
  1849.   memcpy(x, subpath->x, n * sizeof(double));
  1850.   memcpy(y, subpath->y, n * sizeof(double));
  1851.   memcpy(curve, subpath->curve, n * sizeof(GBool));
  1852.   closed = subpath->closed;
  1853. }
  1854.  
  1855. void GfxSubpath::lineTo(double x1, double y1) {
  1856.   if (n >= size) {
  1857.     size += 16;
  1858.     x = (double *)grealloc(x, size * sizeof(double));
  1859.     y = (double *)grealloc(y, size * sizeof(double));
  1860.     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
  1861.   }
  1862.   x[n] = x1;
  1863.   y[n] = y1;
  1864.   curve[n] = gFalse;
  1865.   ++n;
  1866. }
  1867.  
  1868. void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
  1869.                          double x3, double y3) {
  1870.   if (n+3 > size) {
  1871.     size += 16;
  1872.     x = (double *)grealloc(x, size * sizeof(double));
  1873.     y = (double *)grealloc(y, size * sizeof(double));
  1874.     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
  1875.   }
  1876.   x[n] = x1;
  1877.   y[n] = y1;
  1878.   x[n+1] = x2;
  1879.   y[n+1] = y2;
  1880.   x[n+2] = x3;
  1881.   y[n+2] = y3;
  1882.   curve[n] = curve[n+1] = gTrue;
  1883.   curve[n+2] = gFalse;
  1884.   n += 3;
  1885. }
  1886.  
  1887. void GfxSubpath::close() {
  1888.   if (x[n-1] != x[0] || y[n-1] != y[0]) {
  1889.     lineTo(x[0], y[0]);
  1890.   }
  1891.   closed = gTrue;
  1892. }
  1893.  
  1894. GfxPath::GfxPath() {
  1895.   justMoved = gFalse;
  1896.   size = 16;
  1897.   n = 0;
  1898.   firstX = firstY = 0;
  1899.   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
  1900. }
  1901.  
  1902. GfxPath::~GfxPath() {
  1903.   int i;
  1904.  
  1905.   for (i = 0; i < n; ++i)
  1906.     delete subpaths[i];
  1907.   gfree(subpaths);
  1908. }
  1909.  
  1910. // Used for copy().
  1911. GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
  1912.                  GfxSubpath **subpaths1, int n1, int size1) {
  1913.   int i;
  1914.  
  1915.   justMoved = justMoved1;
  1916.   firstX = firstX1;
  1917.   firstY = firstY1;
  1918.   size = size1;
  1919.   n = n1;
  1920.   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
  1921.   for (i = 0; i < n; ++i)
  1922.     subpaths[i] = subpaths1[i]->copy();
  1923. }
  1924.  
  1925. void GfxPath::moveTo(double x, double y) {
  1926.   justMoved = gTrue;
  1927.   firstX = x;
  1928.   firstY = y;
  1929. }
  1930.  
  1931. void GfxPath::lineTo(double x, double y) {
  1932.   if (justMoved) {
  1933.     if (n >= size) {
  1934.       size += 16;
  1935.       subpaths = (GfxSubpath **)
  1936.                    grealloc(subpaths, size * sizeof(GfxSubpath *));
  1937.     }
  1938.     subpaths[n] = new GfxSubpath(firstX, firstY);
  1939.     ++n;
  1940.     justMoved = gFalse;
  1941.   }
  1942.   subpaths[n-1]->lineTo(x, y);
  1943. }
  1944.  
  1945. void GfxPath::curveTo(double x1, double y1, double x2, double y2,
  1946.              double x3, double y3) {
  1947.   if (justMoved) {
  1948.     if (n >= size) {
  1949.       size += 16;
  1950.       subpaths = (GfxSubpath **)
  1951.                    grealloc(subpaths, size * sizeof(GfxSubpath *));
  1952.     }
  1953.     subpaths[n] = new GfxSubpath(firstX, firstY);
  1954.     ++n;
  1955.     justMoved = gFalse;
  1956.   }
  1957.   subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
  1958. }
  1959.  
  1960. void GfxPath::close() {
  1961.   // this is necessary to handle the pathological case of
  1962.   // moveto/closepath/clip, which defines an empty clipping region
  1963.   if (justMoved) {
  1964.     if (n >= size) {
  1965.       size += 16;
  1966.       subpaths = (GfxSubpath **)
  1967.                    grealloc(subpaths, size * sizeof(GfxSubpath *));
  1968.     }
  1969.     subpaths[n] = new GfxSubpath(firstX, firstY);
  1970.     ++n;
  1971.     justMoved = gFalse;
  1972.   }
  1973.   subpaths[n-1]->close();
  1974. }
  1975.  
  1976. //------------------------------------------------------------------------
  1977. // GfxState
  1978. //------------------------------------------------------------------------
  1979.  
  1980. GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
  1981.                    GBool upsideDown) {
  1982.   double k;
  1983.  
  1984.   px1 = pageBox->x1;
  1985.   py1 = pageBox->y1;
  1986.   px2 = pageBox->x2;
  1987.   py2 = pageBox->y2;
  1988.   k = dpi / 72.0;
  1989.   if (rotate == 90) {
  1990.     ctm[0] = 0;
  1991.     ctm[1] = upsideDown ? k : -k;
  1992.     ctm[2] = k;
  1993.     ctm[3] = 0;
  1994.     ctm[4] = -k * py1;
  1995.     ctm[5] = k * (upsideDown ? -px1 : px2);
  1996.     pageWidth = k * (py2 - py1);
  1997.     pageHeight = k * (px2 - px1);
  1998.   } else if (rotate == 180) {
  1999.     ctm[0] = -k;
  2000.     ctm[1] = 0;
  2001.     ctm[2] = 0;
  2002.     ctm[3] = upsideDown ? k : -k;
  2003.     ctm[4] = k * px2;
  2004.     ctm[5] = k * (upsideDown ? -py1 : py2);
  2005.     pageWidth = k * (px2 - px1);
  2006.     pageHeight = k * (py2 - py1);
  2007.   } else if (rotate == 270) {
  2008.     ctm[0] = 0;
  2009.     ctm[1] = upsideDown ? -k : k;
  2010.     ctm[2] = -k;
  2011.     ctm[3] = 0;
  2012.     ctm[4] = k * py2;
  2013.     ctm[5] = k * (upsideDown ? px2 : -px1);
  2014.     pageWidth = k * (py2 - py1);
  2015.     pageHeight = k * (px2 - px1);
  2016.   } else {
  2017.     ctm[0] = k;
  2018.     ctm[1] = 0;
  2019.     ctm[2] = 0;
  2020.     ctm[3] = upsideDown ? -k : k;
  2021.     ctm[4] = -k * px1;
  2022.     ctm[5] = k * (upsideDown ? py2 : -py1);
  2023.     pageWidth = k * (px2 - px1);
  2024.     pageHeight = k * (py2 - py1);
  2025.   }
  2026.  
  2027.   fillColorSpace = new GfxDeviceGrayColorSpace();
  2028.   strokeColorSpace = new GfxDeviceGrayColorSpace();
  2029.   fillColor.c[0] = 0;
  2030.   strokeColor.c[0] = 0;
  2031.   fillPattern = NULL;
  2032.   strokePattern = NULL;
  2033.   fillOpacity = 1;
  2034.   strokeOpacity = 1;
  2035.  
  2036.   lineWidth = 1;
  2037.   lineDash = NULL;
  2038.   lineDashLength = 0;
  2039.   lineDashStart = 0;
  2040.   flatness = 0;
  2041.   lineJoin = 0;
  2042.   lineCap = 0;
  2043.   miterLimit = 10;
  2044.  
  2045.   font = NULL;
  2046.   fontSize = 0;
  2047.   textMat[0] = 1; textMat[1] = 0;
  2048.   textMat[2] = 0; textMat[3] = 1;
  2049.   textMat[4] = 0; textMat[5] = 0;
  2050.   charSpace = 0;
  2051.   wordSpace = 0;
  2052.   horizScaling = 1;
  2053.   leading = 0;
  2054.   rise = 0;
  2055.   render = 0;
  2056.  
  2057.   path = new GfxPath();
  2058.   curX = curY = 0;
  2059.   lineX = lineY = 0;
  2060.  
  2061.   clipXMin = 0;
  2062.   clipYMin = 0;
  2063.   clipXMax = pageWidth;
  2064.   clipYMax = pageHeight;
  2065.  
  2066.   saved = NULL;
  2067. }
  2068.  
  2069. GfxState::~GfxState() {
  2070.   if (fillColorSpace) {
  2071.     delete fillColorSpace;
  2072.   }
  2073.   if (strokeColorSpace) {
  2074.     delete strokeColorSpace;
  2075.   }
  2076.   if (fillPattern) {
  2077.     delete fillPattern;
  2078.   }
  2079.   if (strokePattern) {
  2080.     delete strokePattern;
  2081.   }
  2082.   gfree(lineDash);
  2083.   if (path) {
  2084.     // this gets set to NULL by restore()
  2085.     delete path;
  2086.   }
  2087.   if (saved) {
  2088.     delete saved;
  2089.   }
  2090. }
  2091.  
  2092. // Used for copy();
  2093. GfxState::GfxState(GfxState *state) {
  2094.   memcpy(this, state, sizeof(GfxState));
  2095.   if (fillColorSpace) {
  2096.     fillColorSpace = state->fillColorSpace->copy();
  2097.   }
  2098.   if (strokeColorSpace) {
  2099.     strokeColorSpace = state->strokeColorSpace->copy();
  2100.   }
  2101.   if (fillPattern) {
  2102.     fillPattern = state->fillPattern->copy();
  2103.   }
  2104.   if (strokePattern) {
  2105.     strokePattern = state->strokePattern->copy();
  2106.   }
  2107.   if (lineDashLength > 0) {
  2108.     lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
  2109.     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
  2110.   }
  2111.   saved = NULL;
  2112. }
  2113.  
  2114. void GfxState::getUserClipBBox(double *xMin, double *yMin,
  2115.                                double *xMax, double *yMax) {
  2116.   double ictm[6];
  2117.   double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
  2118.  
  2119.   // invert the CTM
  2120.   det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
  2121.   ictm[0] = ctm[3] * det;
  2122.   ictm[1] = -ctm[1] * det;
  2123.   ictm[2] = -ctm[2] * det;
  2124.   ictm[3] = ctm[0] * det;
  2125.   ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
  2126.   ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
  2127.  
  2128.   // transform all four corners of the clip bbox; find the min and max
  2129.   // x and y values
  2130.   xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
  2131.   yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
  2132.   tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
  2133.   ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
  2134.   if (tx < xMin1) {
  2135.     xMin1 = tx;
  2136.   } else if (tx > xMax1) {
  2137.     xMax1 = tx;
  2138.   }
  2139.   if (ty < yMin1) {
  2140.     yMin1 = ty;
  2141.   } else if (ty > yMax1) {
  2142.     yMax1 = ty;
  2143.   }
  2144.   tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
  2145.   ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
  2146.   if (tx < xMin1) {
  2147.     xMin1 = tx;
  2148.   } else if (tx > xMax1) {
  2149.     xMax1 = tx;
  2150.   }
  2151.   if (ty < yMin1) {
  2152.     yMin1 = ty;
  2153.   } else if (ty > yMax1) {
  2154.     yMax1 = ty;
  2155.   }
  2156.   tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
  2157.   ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
  2158.   if (tx < xMin1) {
  2159.     xMin1 = tx;
  2160.   } else if (tx > xMax1) {
  2161.     xMax1 = tx;
  2162.   }
  2163.   if (ty < yMin1) {
  2164.     yMin1 = ty;
  2165.   } else if (ty > yMax1) {
  2166.     yMax1 = ty;
  2167.   }
  2168.  
  2169.   *xMin = xMin1;
  2170.   *yMin = yMin1;
  2171.   *xMax = xMax1;
  2172.   *yMax = yMax1;
  2173. }
  2174.  
  2175. double GfxState::transformWidth(double w) {
  2176.   double x, y;
  2177.  
  2178.   x = ctm[0] + ctm[2];
  2179.   y = ctm[1] + ctm[3];
  2180.   return w * sqrt(0.5 * (x * x + y * y));
  2181. }
  2182.  
  2183. double GfxState::getTransformedFontSize() {
  2184.   double x1, y1, x2, y2;
  2185.  
  2186.   x1 = textMat[2] * fontSize;
  2187.   y1 = textMat[3] * fontSize;
  2188.   x2 = ctm[0] * x1 + ctm[2] * y1;
  2189.   y2 = ctm[1] * x1 + ctm[3] * y1;
  2190.   return sqrt(x2 * x2 + y2 * y2);
  2191. }
  2192.  
  2193. void GfxState::getFontTransMat(double *m11, double *m12,
  2194.                                double *m21, double *m22) {
  2195.   *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
  2196.   *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
  2197.   *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
  2198.   *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
  2199. }
  2200.  
  2201. void GfxState::setCTM(double a, double b, double c,
  2202.                       double d, double e, double f) {
  2203.   int i;
  2204.  
  2205.   ctm[0] = a;
  2206.   ctm[1] = b;
  2207.   ctm[2] = c;
  2208.   ctm[3] = d;
  2209.   ctm[4] = e;
  2210.   ctm[5] = f;
  2211.  
  2212.   // avoid FP exceptions on badly messed up PDF files
  2213.   for (i = 0; i < 6; ++i) {
  2214.     if (ctm[i] > 1e10) {
  2215.       ctm[i] = 1e10;
  2216.     } else if (ctm[i] < -1e10) {
  2217.       ctm[i] = -1e10;
  2218.     }
  2219.   }
  2220. }
  2221.  
  2222. void GfxState::concatCTM(double a, double b, double c,
  2223.                          double d, double e, double f) {
  2224.   double a1 = ctm[0];
  2225.   double b1 = ctm[1];
  2226.   double c1 = ctm[2];
  2227.   double d1 = ctm[3];
  2228.   int i;
  2229.  
  2230.   ctm[0] = a * a1 + b * c1;
  2231.   ctm[1] = a * b1 + b * d1;
  2232.   ctm[2] = c * a1 + d * c1;
  2233.   ctm[3] = c * b1 + d * d1;
  2234.   ctm[4] = e * a1 + f * c1 + ctm[4];
  2235.   ctm[5] = e * b1 + f * d1 + ctm[5];
  2236.  
  2237.   // avoid FP exceptions on badly messed up PDF files
  2238.   for (i = 0; i < 6; ++i) {
  2239.     if (ctm[i] > 1e10) {
  2240.       ctm[i] = 1e10;
  2241.     } else if (ctm[i] < -1e10) {
  2242.       ctm[i] = -1e10;
  2243.     }
  2244.   }
  2245. }
  2246.  
  2247. void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
  2248.   if (fillColorSpace) {
  2249.     delete fillColorSpace;
  2250.   }
  2251.   fillColorSpace = colorSpace;
  2252. }
  2253.  
  2254. void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
  2255.   if (strokeColorSpace) {
  2256.     delete strokeColorSpace;
  2257.   }
  2258.   strokeColorSpace = colorSpace;
  2259. }
  2260.  
  2261. void GfxState::setFillPattern(GfxPattern *pattern) {
  2262.   if (fillPattern) {
  2263.     delete fillPattern;
  2264.   }
  2265.   fillPattern = pattern;
  2266. }
  2267.  
  2268. void GfxState::setStrokePattern(GfxPattern *pattern) {
  2269.   if (strokePattern) {
  2270.     delete strokePattern;
  2271.   }
  2272.   strokePattern = pattern;
  2273. }
  2274.  
  2275. void GfxState::setLineDash(double *dash, int length, double start) {
  2276.   if (lineDash)
  2277.     gfree(lineDash);
  2278.   lineDash = dash;
  2279.   lineDashLength = length;
  2280.   lineDashStart = start;
  2281. }
  2282.  
  2283. void GfxState::clearPath() {
  2284.   delete path;
  2285.   path = new GfxPath();
  2286. }
  2287.  
  2288. void GfxState::clip() {
  2289.   double xMin, yMin, xMax, yMax, x, y;
  2290.   GfxSubpath *subpath;
  2291.   int i, j;
  2292.  
  2293.   xMin = xMax = yMin = yMax = 0; // make gcc happy
  2294.   for (i = 0; i < path->getNumSubpaths(); ++i) {
  2295.     subpath = path->getSubpath(i);
  2296.     for (j = 0; j < subpath->getNumPoints(); ++j) {
  2297.       transform(subpath->getX(j), subpath->getY(j), &x, &y);
  2298.       if (i == 0 && j == 0) {
  2299.         xMin = xMax = x;
  2300.         yMin = yMax = y;
  2301.       } else {
  2302.         if (x < xMin) {
  2303.           xMin = x;
  2304.         } else if (x > xMax) {
  2305.           xMax = x;
  2306.         }
  2307.         if (y < yMin) {
  2308.           yMin = y;
  2309.         } else if (y > yMax) {
  2310.           yMax = y;
  2311.         }
  2312.       }
  2313.     }
  2314.   }
  2315.   if (xMin > clipXMin) {
  2316.     clipXMin = xMin;
  2317.   }
  2318.   if (yMin > clipYMin) {
  2319.     clipYMin = yMin;
  2320.   }
  2321.   if (xMax < clipXMax) {
  2322.     clipXMax = xMax;
  2323.   }
  2324.   if (yMax < clipYMax) {
  2325.     clipYMax = yMax;
  2326.   }
  2327. }
  2328.  
  2329. void GfxState::textShift(double tx, double ty) {
  2330.   double dx, dy;
  2331.  
  2332.   textTransformDelta(tx, ty, &dx, &dy);
  2333.   curX += dx;
  2334.   curY += dy;
  2335. }
  2336.  
  2337. void GfxState::shift(double dx, double dy) {
  2338.   curX += dx;
  2339.   curY += dy;
  2340. }
  2341.  
  2342. GfxState *GfxState::save() {
  2343.   GfxState *newState;
  2344.  
  2345.   newState = copy();
  2346.   newState->saved = this;
  2347.   return newState;
  2348. }
  2349.  
  2350. GfxState *GfxState::restore() {
  2351.   GfxState *oldState;
  2352.  
  2353.   if (saved) {
  2354.     oldState = saved;
  2355.  
  2356.     // these attributes aren't saved/restored by the q/Q operators
  2357.     oldState->path = path;
  2358.     oldState->curX = curX;
  2359.     oldState->curY = curY;
  2360.     oldState->lineX = lineX;
  2361.     oldState->lineY = lineY;
  2362.  
  2363.     path = NULL;
  2364.     saved = NULL;
  2365.     delete this;
  2366.  
  2367.   } else {
  2368.     oldState = this;
  2369.   }
  2370.  
  2371.   return oldState;
  2372. }
  2373.